//
//  ETHJsonRpcKit.m
//  CryptoGirl
//
//  Created by yiren on 2018/6/11.
//  Copyright © 2018年 邓昊. All rights reserved.
//
#import <ethers/ethers.h>
#import "ETHJsonRpcKit.h"
#import "KitConfig.h"
#import "FadeOutView.h"
#import <AFNetworking/AFNetworking.h>
#import "BigNumber.h"
#import "Signature.h"
#import "Account.h"
#import "RLPSerialization.h"

@implementation ETHJsonRpcKit
#pragma mark - 初始化
+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    static ETHJsonRpcKit *kit = nil;
    dispatch_once(&onceToken, ^{
        kit = [[ETHJsonRpcKit alloc]init];
        kit.sessionManager = [AFHTTPSessionManager manager];
        kit.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
        kit.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
//        kit.sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/plain",nil];
//        [kit.sessionManager.requestSerializer setValue:@"text/plain" forHTTPHeaderField:@"Accept"];
//        [kit.sessionManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        kit.endPoint = @"https://rinkeby.infura.io/HZ7akc0jwna5cI2GpRW8";
        NSDictionary *dic = [[NSUserDefaults standardUserDefaults]objectForKey:kCurrentAccount];
        if (dic) {
          [kit getAccountWithDic:dic];
        }
//
    });
    
    return kit;
}
#pragma mark - 钱包API
//获取当前账户
- (void)getAccountWithDic: (NSDictionary *)dic {
    
//    NSLog(@"当前用户 = %@",dic);
    NSData *data = [ETHJsonRpcKit convertHexStrToData:dic[kUserKey]];
    Account *account = [Account accountWithPrivateKey:data];
    self.account = account;
    
}
//创建账户
- (void)creatAccountWithPassword:(NSString *)password accountName:(NSString *)name {
    Account *account = [Account randomMnemonicAccount];
    //    NSString *result = [[NSString alloc] initWithData:account.privateKey encoding:NSASCIIStringEncoding];
    WS(ws);
    Cancellable *cancel = [account encryptSecretStorageJSON:password callback:^(NSString *json) {
        //        NSLog(@"json = %@",json);
        NSString *addr = [NSString stringWithFormat:@"%@",account.address];
        [ws saveAccount:json andAddress:addr andKey:account.privateKey andName:name andPhrase:account.mnemonicPhrase andPassword:password];
    }];
}
//导入账户
- (void)importAccountWithPassword:(NSString *)password accountName:(NSString *)name key:(NSString *)keyphrase andType:(NSInteger)type {
    switch (type) {//mem
        case 0:{
            BOOL valid = [Account isValidMnemonicPhrase:keyphrase];
            if (valid == NO) {
                if (isVertical) {
                    showFadeOutView(@"助记词格式有误", YES, 1.5);
                }else {
                    showFadeOutHorizentalView(@"助记词格式有误", YES, 1.5);
                }
                
                [self failBlockAction];
                return;
            }
            Account *account = [Account accountWithMnemonicPhrase:keyphrase];
            WS(ws);
            Cancellable *cancel = [account encryptSecretStorageJSON:password callback:^(NSString *json) {
                //        NSLog(@"json = %@",json);
                NSString *addr = [NSString stringWithFormat:@"%@",account.address];
                [ws saveAccount:json andAddress:addr andKey:account.privateKey andName:name andPhrase:account.mnemonicPhrase andPassword:password];
            }];
            break;
        }
        case 1:{//keystore
            WS(ws);
            Cancellable *can2 = [Account decryptSecretStorageJSON:keyphrase password:password callback:^(Account *account, NSError *error) {
                if (!account) {
                    NSLog(@"获取不到account");
                    if (isVertical) {
                        showFadeOutView(@"密码不正确或Keystore错误", YES, 1.5);
                    }else {
                        showFadeOutHorizentalView(@"密码不正确或Keystore错误", YES, 1.5);
                    }
                    [ws failBlockAction];
                    return;
                }
                if (error) {
                    NSLog(@"error = %@",error);
                    if (isVertical) {
                        showFadeOutView(@"密码不正确或Keystore错误", YES, 1.5);
                    }else {
                        showFadeOutHorizentalView(@"密码不正确或Keystore错误", YES, 1.5);
                    }
                    [ws failBlockAction];
                    return;
                }
                NSString *addr = [NSString stringWithFormat:@"%@",account.address];
                if ([addr length] == 0) {
                    if (isVertical) {
                        showFadeOutView(@"密码不正确或Keystore错误", YES, 1.5);
                    }else {
                        showFadeOutHorizentalView(@"密码不正确或Keystore错误", YES, 1.5);
                    }
                    [ws failBlockAction];
                    return;
                }
                NSLog(@"执行导入");
                [ws saveAccount:keyphrase andAddress:addr andKey:account.privateKey andName:name andPhrase:account.mnemonicPhrase andPassword:password];
                
            }];
            break;
        }
        case 2:{//privatekey
            NSData *data = [ETHJsonRpcKit convertHexStrToData:keyphrase];
            Account *account = [Account accountWithPrivateKey:data];
            NSLog(@"address = %@ /n key = %@ str = %@",account.address,account.privateKey,keyphrase);
            WS(ws);
            if (!account.address) {
                
                if (isVertical) {
                    showFadeOutView(@"privatekey不正确", YES, 1.5);
                }else {
                    showFadeOutHorizentalView(@"privatekey不正确", YES, 1.5);
                }
                NSLog(@"不正确！！！");
                if (self.responseBlock) {
                    self.responseBlock(NO);
        
                }
//                [ws failBlockAction];
            }else {
                Cancellable *can = [account encryptSecretStorageJSON:password callback:^(NSString *json) {
                    NSLog(@"key json = %@",json);
                    NSString *addr = [NSString stringWithFormat:@"%@",account.address];
                    if ([addr length] == 0) {
                        if (isVertical) {
                            showFadeOutView(@"privatekey不正确", YES, 1.5);
                        }else {
                            showFadeOutHorizentalView(@"privatekey不正确", YES, 1.5);
                        }
                        
                        [ws failBlockAction];
                    }else {
                        [ws saveAccount:json andAddress:addr andKey:account.privateKey andName:name andPhrase:account.mnemonicPhrase andPassword:password];
                    }
                    
                }];
            }
            
            break;
        }
        default:
            break;
    }
}

- (void)getBalanceForAccount:(NSString *)address {
    WS(ws);
    
    NSArray *arr = [NSArray arrayWithObjects:address,@"latest", nil];
    [self invokeMethod:@"eth_getBalance" withParameters:arr response:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (!error) {
            NSLog(@"balance = %@",responseObject);
            if (responseObject[@"result"]) {
                BigNumber *bigBal = [BigNumber bigNumberWithHexString:responseObject[@"result"]];
                BigNumber *bigWei = [BigNumber bigNumberWithDecimalString:kWei];
                BigNumber *bigGWei = [BigNumber bigNumberWithDecimalString:kGwei];
                bigWei = [bigWei div:bigGWei];
                bigBal = [bigBal div:bigGWei];
                
                //                bigBal = [bigBal div:bigWei];
                double bal = [bigBal.decimalString doubleValue]/[bigWei.decimalString doubleValue];
//                return [NSString stringWithFormat:@"%.4f",bal];
                if (ws.balanceBlock) {
                    ws.balanceBlock([NSString stringWithFormat:@"%.6f",bal]);
                }
            }else {
                NSLog(@"balance error??111111111");
            }
            
        } else {
            //            showFadeOutView(@"已注册登录", YES, 1.5);
            
            if (ws.balanceBlock) {
                
                ws.balanceBlock(@"0.00");
            }
            NSLog(@"balance error = %@",error.localizedDescription);
            
            if (isVertical) {
                showFadeOutView(@"获取余额错误", YES, 1.5);
            }else {
                showFadeOutHorizentalView(@"获取余额错误", YES, 1.5);
            }
//            return @"0";
        }
    }];
}

- (void)getBalanceForAccountList:(NSString *)address {
    WS(ws);
    NSArray *arr = [NSArray arrayWithObjects:address,@"latest", nil];
    [self invokeMethod:@"eth_getBalance" withParameters:arr response:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (!error) {
            NSLog(@"balance = %@",responseObject);
            if (responseObject[@"result"]) {
                BigNumber *bigBal = [BigNumber bigNumberWithHexString:responseObject[@"result"]];
                BigNumber *bigWei = [BigNumber bigNumberWithDecimalString:kWei];
                BigNumber *bigGWei = [BigNumber bigNumberWithDecimalString:kGwei];
                bigWei = [bigWei div:bigGWei];
                bigBal = [bigBal div:bigGWei];
                
                //                bigBal = [bigBal div:bigWei];
                double bal = [bigBal.decimalString doubleValue]/[bigWei.decimalString doubleValue];
                [ws setBalanceForAddress:address andValue:[NSString stringWithFormat:@"%.6f",bal]];
                //                return [NSString stringWithFormat:@"%.4f",bal];
                if (ws.balanceBlock) {
                    ws.balanceBlock([NSString stringWithFormat:@"%.6f",bal]);
                }
            }
            
        } else {
            //            showFadeOutView(@"已注册登录", YES, 1.5);
            NSLog(@"balance error = %@",error.localizedDescription);
            if (isVertical) {
                showFadeOutView(@"获取余额错误", YES, 1.5);
            }else {
                showFadeOutHorizentalView(@"获取余额错误", YES, 1.5);
            }
            
            //            return @"0";
        }
    }];
}

- (void)setBalanceForAddress:(NSString *)address andValue:(NSString *)balance {
    NSArray *arr = [[NSUserDefaults standardUserDefaults]objectForKey:kUserArray];
    NSMutableArray *marr = [NSMutableArray arrayWithArray:arr];
    if ([arr count] > 0) {
        for (int i = 0; i<[arr count]; i++) {
            NSDictionary *dic = arr[i];
            if ([dic[kUserAddress] isEqualToString:address]) {
                NSMutableDictionary *mdic = [NSMutableDictionary dictionaryWithDictionary:dic];
                [mdic setObject:balance forKey:kUserBalance];
                [marr replaceObjectAtIndex:i withObject:mdic];
                [[NSUserDefaults standardUserDefaults]setObject:marr forKey:kUserArray];
                [[NSUserDefaults standardUserDefaults]synchronize];
            }
        }
    }
}

#pragma mark - 离线操作部分
- (void)saveAccount : (NSString *)json andAddress: (NSString *)address andKey: (NSData *)data andName: (NSString *)name andPhrase:(NSString *)phrase andPassword: (NSString *)password{
    //检测重复
    NSMutableArray *arr1 = [[NSUserDefaults standardUserDefaults] objectForKey:kUserArray];
    for (NSDictionary *dic in arr1) {
        if ([name isEqualToString:dic[kUserName]]) {
            
            if (isVertical) {
                showFadeOutView(@"账户名已存在", YES, 1.5);
            }else {
                showFadeOutHorizentalView(@"账户名已存在", YES, 1.5);
            }
            [self failBlockAction];
            return;
        }
    }
    for (NSDictionary *dic in arr1) {
        if ([address isEqualToString:dic[kUserAddress]]) {
            [self failBlockAction];
            if (isVertical) {
                showFadeOutView(@"账户地址已存在", YES, 1.5);
            }else {
                showFadeOutHorizentalView(@"账户地址已存在", YES, 1.5);
            }
            return;
        }
    }
    
    NSString *keyStr = [SecureData dataToHexString:data];
    keyStr = [keyStr substringFromIndex:2];
    NSString *testkey = [ETHJsonRpcKit convertDataToHexStr:data];
    NSLog(@"address = %@ \n json = %@ key = %@ testkey = %@",address,json,keyStr,testkey);
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    self.userDic = [NSMutableDictionary dictionary];
    
    [self.userDic setValue:json forKey:kUserJson];
    [self.userDic setValue:address forKey:kUserAddress];
    [self.userDic setValue:keyStr forKey:kUserKey];
    [self.userDic setValue:name forKey:kUserName];
    [self.userDic setValue:phrase forKey:kUserPhrase];
    [self.userDic setValue:password forKey:kUserPassword];
    
    NSMutableArray *array = [NSMutableArray array];
    
    NSMutableArray *arr = [defaults objectForKey:kUserArray];
    if ([arr count] != 0) {
        array = [NSMutableArray arrayWithArray:arr];
    }
    [array addObject:self.userDic];
    [defaults setObject:array forKey:kUserArray];
    [defaults setObject:self.userDic forKey:kCurrentAccount];
    //    array = [[NSUserDefaults standardUserDefaults]objectForKey:kUserArray];
    [defaults synchronize];
    [self getAccountWithDic:self.userDic];
    if (self.accountInfoBlock) {
        self.accountInfoBlock(self.userDic);
    }
    if (self.responseBlock) {
        self.responseBlock(YES);
    }
    if ([arr count] != 0) {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"notificationchangewallet" object:nil];
    }
//    showFadeOutView(@"操作成功", YES, 1.5);
}

- (void)failBlockAction {
    if (self.responseBlock) {
        self.responseBlock(NO);
    }
}

- (void)successBlockAction {
    if (self.responseBlock) {
        self.responseBlock(YES);
    }
}

- (void) sendTransaction:(NSDictionary *)dic {
    if (!self.account) {
        NSDictionary *dic = [[NSUserDefaults standardUserDefaults]objectForKey:kCurrentAccount];
        if (dic) {
            [self getAccountWithDic:dic];
        }
        if (!self.account) {
            
            if (isVertical) {
                showFadeOutView(@"无法获取账户", YES, 1.5);
            }else {
                showFadeOutHorizentalView(@"无法获取账户", YES, 1.5);
            }
            return;
        }
    }else {
        
        
        if (isVertical) {
            showFadeOutView(@"正在加载可能存在延时", YES, 1.5);
        }else {
            showFadeOutHorizentalView(@"正在加载可能存在延时", YES, 1.5);
        }
        Transaction *transaction = [Transaction transactionWithFromAddress:self.account.address];
        Address *toAddr = [Address addressWithString:dic[@"conAddress"]];
        transaction.toAddress = toAddr;
        BigNumber *bignonce = [BigNumber bigNumberWithHexString:dic[@"nonce"]];
        NSLog(@"big = %@",bignonce.decimalString);
        transaction.nonce = [bignonce.decimalString integerValue];
        transaction.gasPrice = [BigNumber bigNumberWithHexString:dic[@"gasPrice"]];
        transaction.gasLimit = [BigNumber bigNumberWithHexString:dic[@"gasNum"]];
        transaction.value = [BigNumber bigNumberWithHexString:dic[@"ethNum"]];
        NSString *str = dic[@"conData"];
        str = [str substringFromIndex:2];
        transaction.data = [ETHJsonRpcKit convertHexStrToData:str];
        [self.account sign:transaction];
        
        NSData *transData = [transaction serialize];
        [self sendRawTransaction:transData];
    }
}

- (void)sendRawTransaction: (NSData *)data {
    NSString *str = [ETHJsonRpcKit convertDataToHexStr:data];
    str = [NSString stringWithFormat:@"0x%@",str];
    NSLog(@"rawData = %@", str);
    NSArray *array = [[NSArray alloc]initWithObjects:str,nil];
    WS(ws);
    [self invokeMethod:@"eth_sendRawTransaction" withParameters:array response:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (error) {
            
            if (isVertical) {
                showFadeOutView(@"发起交易失败", YES, 1.5);
            }else {
                showFadeOutHorizentalView(@"发起交易失败", YES, 1.5);
            }
            NSLog(@"rawTran Error = %@",error);
            [ws failBlockAction];
        }else {
            NSLog(@"RawTransaction= %@",responseObject);
            if (responseObject[@"error"]) {
                if (isVertical) {
                    showFadeOutView(@"发起交易失败", YES, 1.5);
                }else {
                    showFadeOutHorizentalView(@"发起交易失败", YES, 1.5);
                }
                [ws failBlockAction];
            }else {
                if (responseObject[@"result"]) {
                    [UIPasteboard generalPasteboard].string = str;
                    [ws getReceipt:responseObject[@"result"]];
                }
            }
            
        }
    }];
}

- (void)getReceipt:(NSString *)response {
    WS(ws);
    NSArray *arr = [NSArray arrayWithObject:response];
    [self invokeMethod:@"eth_getTransactionReceipt" withParameters:arr response:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        [[NSNotificationCenter defaultCenter]postNotificationName:@"hidetrans" object:nil];
        if (error) {
            NSLog(@"receipt Error = %@",error);
            [ws failBlockAction];
            showFadeOutView(error.localizedDescription, YES, 1.5);
        }else {
            NSLog(@"receipt= %@",responseObject);
            if (isVertical) {
                showFadeOutView(@"发起交易成功", YES, 1.5);
            }else {
                showFadeOutHorizentalView(@"发起交易成功", YES, 1.5);
            }
            [ws successBlockAction];
        }
    }];
}

- (void)ethCall:(NSString *)toAddress andContract: (NSString *)conData response:(void (^)(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error))response {
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    NSDictionary *accdic = [[NSUserDefaults standardUserDefaults]objectForKey:kCurrentAccount];
    dic = @{@"from": accdic[kUserAddress],
            @"to": toAddress,
            @"data": conData
            };
    NSString * str = @"latest";
    NSArray *array = [NSArray arrayWithObjects:dic,str,nil];
    WS(ws);
    [self invokeMethod:@"eth_call" withParameters:array response:response];
}

- (void)ethRpcSign:(NSString *)message {
    
}

- (void)ethSign:(NSString *)str {
    if (self.account) {// 有问题！！！！！！！！！！
        
        NSLog(@"address = %@ str = %@",self.account.address,str);
        NSError *error;
        NSData *strdata = [SecureData hexStringToData:str];
        NSLog(@"sds");
        Signature *sig = [self.account signMessage:strdata];
        NSLog(@"desc = %@",sig.description);
    }
}

- (void)ethSignData:(NSData *)data {
    if (self.account) {
        Signature *sig = [self.account signMessage:data];
        NSLog(@"desc = %@",sig.description);
        if (sig.r) {
            SecureData *signatureData = [SecureData secureDataWithCapacity:65];
            [signatureData appendData:sig.r];
            [signatureData appendData:sig.s];
            [signatureData appendByte:sig.v + 27];
            
            NSString *signedStr = [SecureData dataToHexString:signatureData.data];
            if (self.signedBlock) {
                self.signedBlock(signedStr);
            }
        }
    }else {
        NSLog(@"NO ACCOUNT");
    }
}

//af网络部分封装
- (void)invokeMethod:(NSString *)method
      withParameters:(id)parameters
             response:(void (^)(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error))response
{
    [self invokeMethod:method withParameters:parameters requestId:@(1) response:response];
}

- (void)invokeMethod:(NSString *)method
      withParameters:(id)parameters
           requestId:(id)requestId
             response:(void (^)(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error))response
{
    NSMutableURLRequest *request = [self requestWithMethod:method parameters:parameters requestId:requestId];
    

//    [[self.sessionManager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:response] resume];
    self.sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/plain", nil];
//    [self.sessionManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
    [[self.sessionManager dataTaskWithRequest:request completionHandler:response]resume];
}

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                parameters:(id)parameters
                                 requestId:(id)requestId
{
    NSParameterAssert(method);
    
    if (!parameters) {
        parameters = @[];
    }
    
    NSAssert([parameters isKindOfClass:[NSDictionary class]] || [parameters isKindOfClass:[NSArray class]], @"Expect NSArray or NSDictionary in JSONRPC parameters");
    
    if (!requestId) {
        requestId = @(1);
    }
    
    NSMutableDictionary *payload = [NSMutableDictionary dictionary];
    payload[@"jsonrpc"] = @"2.0";
    payload[@"method"] = method;
    payload[@"params"] = parameters;
    payload[@"id"] = @(1);
    NSDictionary *dic = @{@"jsonrpc":@"2.0",@"method":method,@"params":parameters,@"id":@(1)};
    NSMutableURLRequest *request = [self.sessionManager.requestSerializer requestWithMethod:@"POST" URLString:self.endPoint parameters:nil error:nil];
    NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
    [request setHTTPBody:data];
//    NSLog(@"payload = %@ end = %@ dic = %@",payload,self.endPoint,dic);
    
    return request;
}

#pragma mark - parameter calculate
- (NSString *)calculateParameterWithType:(NSInteger )type andValue:(NSString *)value {
    NSString *resultStr;
    switch (type) {
        case 0:{//uint
            
            break;
        }
        case 1:{//address
            NSString *prefix = [value substringToIndex:2];
            if ([prefix isEqualToString:@"0x"]) {
                value = [value substringFromIndex:2];
                return [NSString stringWithFormat:@"000000000000000000000000%@",value];
            }else {
                return [NSString stringWithFormat:@"000000000000000000000000%@",value];
            }
            break;
        }
        case 2:{//bool
            if ([value isEqualToString:@"YES"]) {
                return @"0000000000000000000000000000000000000000000000000000000000000001";
            }else {
                return @"0000000000000000000000000000000000000000000000000000000000000000";
            }
            break;
        }
        case 3:{//uint256
            NSString *prefix = [value substringToIndex:2];
            if ([prefix isEqualToString:@"0x"]) {
                value = [value substringFromIndex:2];
                NSString *zeroStr = @"0000000000000000000000000000000000000000000000000000000000000000";
                NSInteger zeroCount = 64 - [value length];
                NSString *dataStr = [zeroStr substringWithRange:NSMakeRange(0, zeroCount)];
                dataStr = [dataStr stringByAppendingString:value];
                return dataStr;
            }else {
                NSString *zeroStr = @"0000000000000000000000000000000000000000000000000000000000000000";
                NSInteger zeroCount = 64 - [value length];
                NSString *dataStr = [zeroStr substringWithRange:NSMakeRange(0, zeroCount)];
                dataStr = [dataStr stringByAppendingString:value];
                return dataStr;
            }
            break;
        }
        case 4:{//byte
            
            break;
        }
        case 5:{//array
            
            break;
        }
        default:
            break;
    }
    return resultStr;
}

#pragma mark - util
+ (NSString *)sha3:(NSString *)str {
    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
    NSData *condata = [SecureData KECCAK256:data];
    NSString *constr = [ETHJsonRpcKit convertDataToHexStr:condata];
    
    constr = [constr substringToIndex:8];
    NSString *shastr = [NSString stringWithFormat:@"0x%@",constr];
    return shastr;
}

+ (NSString *)fullSha3:(NSString *)str {
    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
    NSData *condata = [SecureData KECCAK256:data];
    NSString *constr = [ETHJsonRpcKit convertDataToHexStr:condata];
    NSString *shastr = [NSString stringWithFormat:@"0x%@",constr];
    return shastr;
}
// NSDATA 16进制转换
+ (NSString *)convertDataToHexStr:(NSData *)data {
    if (!data || [data length] == 0) {
        return @"";
    }
    NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
    
    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
        unsigned char *dataBytes = (unsigned char*)bytes;
        for (NSInteger i = 0; i < byteRange.length; i++) {
            NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
            if ([hexStr length] == 2) {
                [string appendString:hexStr];
            } else {
                [string appendFormat:@"0%@", hexStr];
            }
        }
    }];
    
    return string;
}
//16进制转NSDATA
+ (NSData *)convertHexStrToData:(NSString *)str {
    if (!str || [str length] == 0) {
        return nil;
    }
    
    NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
    NSRange range;
    if ([str length] % 2 == 0) {
        range = NSMakeRange(0, 2);
    } else {
        range = NSMakeRange(0, 1);
    }
    for (NSInteger i = range.location; i < [str length]; i += 2) {
        unsigned int anInt;
        NSString *hexCharStr = [str substringWithRange:range];
        NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
        
        [scanner scanHexInt:&anInt];
        NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
        [hexData appendData:entity];
        
        range.location += range.length;
        range.length = 2;
    }
    
    //    LEDEBUG(@"hexdata: %@", hexData);
    return hexData;
}


@end
